﻿using HCenter.CacheHelper;
using Polly;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace cachehelperTest
{
    class Program
    {
        static void Main(string[] args)
        {
                //int minWorker, minIOC;
                //// Get the current settings.
                //ThreadPool.GetMinThreads(out minWorker, out minIOC);
                //// Change the minimum number of worker threads to four, but
                //// keep the old setting for minimum asynchronous I/O 
                //// completion threads.
                //ThreadPool.SetMinThreads(4, minIOC);
            try
            {

                ICacheProvider cache =
                    //new MemoryCacheImp("vive") { KeySuffix = "xjh" };
                    new CSRedisCacheImp("vive", 1) { KeySuffix = "xjh" };


                //StackExchange(cache);

                Test_SetValue(cache);
                Test_GetValue_Tasks(cache);
                //CallWithTimeout(FiveSecondMethod, 4000);
                

                //TestPolicy();
                System.Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
                System.Console.ReadKey();
            }
        }
        static void Test_SetValue(ICacheProvider cache)
        {
            cache.RemoveAll();
            #region Hash

            cache.HashSet("user", "u1", "123");
            cache.HashSet("user", "u2", "1234");
            cache.HashSet("user", "u3", "1235");
            var news = cache.HashGet<string>("user", "u2");

            #endregion Hash

            List<Person> people = new List<Person>()
            {
                new Person(1, "Joe", new List<Contact>()
                {
                    new Contact("1", "0123456789"),
                    new Contact("2", "0234567890")
                }),
                new Person(2, "Joe2", new List<Contact>()
                {
                    new Contact("12", "1234567289"),
                    new Contact("22", "2345672890")
                })
            };
            //for(var i = 2; i < 3003; i++)
            //{
            //    people.Add(new Person(i, "Joe2" + i, new List<Contact>()
            //    {
            //        new Contact("12"+i, "1234567289"+i),
            //        new Contact("22"+i, "2345672890"+i)
            //    }));
            //}

            cache.Set("People", people);
            var getpeople = cache.Get<List<Person>>("People");

            var ret = cache.HashSet("user", "Peoples", people);
            var pps = cache.HashGet<List<Person>>("user", "Peoples");

            ret = cache.HashSet("user", "People", people[1]);

            var pp2s = cache.HashGet<List<Person>>("user", "Peoples");
            var pp = cache.HashGet<Person>("user", "People");


            Dictionary<string, Person> dicPerson = new Dictionary<string, Person>();
            people.ForEach(p => dicPerson[p.Id.ToString()] = p);
            var dics = new Dictionary<string, Dictionary<string, Person>>();
            dics.Add("dicpeople", dicPerson);

           // cache.HashSetExecute("dicpeople", dicPerson);

            cache.HashSetExecute(dics);
            var dicpeoples = cache.HashGetAll<Person>("dicpeople");

            var keys = cache.HashGetAll<object>("user");
        }
        static void Test_GetValue_Tasks(ICacheProvider cache)
        {
            #region Test_GetValue_Tasks
            const int noOfClients = 10000;
            var tasks = new Task[noOfClients];
            var c = 0;
            var ie = 0;
            var locked = 0;
            var watch1 = new Stopwatch();
            //开始计时
            watch1.Start();
            cache.Set("atomic-counter", 0);
            for (var i = 0; i < noOfClients; i++)
            {
                Thread.Sleep(10);
                tasks[i] = Task.Factory.StartNew((object clientNo) =>
                {
                    try
                    {
                        var token = Environment.MachineName;
                        //if (cache.LockTake("lock_test", token, TimeSpan.MaxValue))
                        using (cache.AcquireLock("lock_test", TimeSpan.FromSeconds(20),true))
                        {
                            try
                            {
                                //TODO:开始做你需要的事情
                                //Thread.Sleep(5000);
                                var watch = new Stopwatch();
                                //开始计时
                                watch.Start();

                                if (!cache.Exists("atomic-counter")) cache.Set("atomic-counter", 0);

                                var contacts = cache.Get<List<Person>>("People");
                                var contactslist = cache.HashGet<List<Person>>("user", "Peoples");
                                //var contactslist = cache.HashGetAll<List<Person>>("user");

                                Thread.Sleep(10);

                                var counter = cache.Get<int>("atomic-counter");
                                cache.Set("atomic-counter", (counter + 1));
                                var atomiccounter = cache.Get<int>("atomic-counter");

                                watch.Stop();

                                Console.WriteLine(cache.GetType().Name + " client {0} released lock,contactslist.Count={1},watch.ElapsedMilliseconds={2},atomic-counter={3}", (int)clientNo, contactslist.Count, watch.ElapsedMilliseconds, atomiccounter);
                            }
                            finally
                            {
                                //cache.LockRelease("lock_test", token);
                            }
                        }
                        //else
                        //{
                        //    locked++;
                        //    var atomiccounter = cache.Get<int>("atomic-counter");
                        //    Console.WriteLine(cache.GetType().Name + " client {0} ,locked={1},atomic-counter={2},is locked:", locked, (int)clientNo, atomiccounter);
                        //}
                    }
                    catch (Exception e)
                    {
                        ie++;
                        var atomiccounter = cache.Get<int>("atomic-counter");
                        Console.WriteLine(cache.GetType().Name + " client {0} ,ie={1},atomic-counter={2},Exception:" + e.Message, ie, (int)clientNo, atomiccounter);
                    }

                    c++;
                    if (noOfClients <= c)
                    {
                        watch1.Stop();
                        var atomiccounter = cache.Get<int>("atomic-counter");
                        Console.WriteLine(cache.GetType().Name + " client c={0},ie={1},ElapsedMilliseconds={2} ,atomic-counter={3}", c, ie, watch1.ElapsedMilliseconds, atomiccounter);
                    }

                }, i + 1);
            }
            #endregion
        }

        static void StackExchange(ICacheProvider cache)
        {
            DateTime time0 = DateTime.Now;
            DateTime time1 = DateTime.Now;

            #region  StackExchange.Redis
            {
                var time = 10000;
                time0 = DateTime.Now;
                for (int i = 0; i < time; i++)
                {
                    var rets = cache.Set("AAAA", "AAAAAAA");
                }
                time1 = DateTime.Now;
                Console.WriteLine($"{cache.GetType().Name} 赋值 {time} 次, 耗时: {0} 秒, {1} 毫秒", (time1 - time0).TotalSeconds, (time1 - time0).TotalMilliseconds);

                string valueStr = "";
                time0 = DateTime.Now;
                for (int i = 0; i < time; i++)
                {
                    var value = cache.Get<string>("AAAA");
                    valueStr = value;
                }
                time1 = DateTime.Now;
                Console.WriteLine($"{cache.GetType().Name} 取值 {time} 次, 耗时: {0} 秒, {1} 毫秒", (time1 - time0).TotalSeconds, (time1 - time0).TotalMilliseconds);
                Console.WriteLine(valueStr);
                Console.WriteLine("----------------------------------");
            }

            #endregion
        }

        public static void FiveSecondMethod()
        {
            System.Threading.Thread.Sleep(5000);
            Console.WriteLine("FiveSecondMethod");
        }
        public static void CallWithTimeout(Action action, int timeoutMilliseconds)
        {
            if (action == null) return;
            System.Threading.Thread threadToKill = null;
            Action wrappedAction = () =>
            {
                threadToKill = System.Threading.Thread.CurrentThread;
                action.Invoke();
            };
            var result = wrappedAction.BeginInvoke(null, null);
            if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
            {
                wrappedAction.EndInvoke(result);
            }
            else
            {
                threadToKill.Abort();
                throw new Exception("请求超时");
            }
        }

        private static int times = 0;

        public static void TestPolicy()
        {
            //var policy = Policy
            //  .Handle<Exception>()
            //  .WaitAndRetry(new[]
            //  {
            //    TimeSpan.FromSeconds(1),
            //    TimeSpan.FromSeconds(3),
            //    TimeSpan.FromSeconds(7)
            //  }, (exception, retryCount, context) => // 出异常会执行以下代码
            //    {
            //        Console.WriteLine($"exception:{ exception.Message}, retryCount:{retryCount}, id:{context["id"]}, name:{context["name"]}");
            //    });
            ////  .Retry(3, (exception, retryCount, context) => // 出异常会执行以下代码
            ////{
            ////    Console.WriteLine($"exception:{ exception.Message}, retryCount:{retryCount}, id:{context["id"]}, name:{context["name"]}");
            ////});

            try
            {
                // // 通过 new Context 传递上下文信息
                // var result = policy.Execute<string>(Test, new Context("data", new Dictionary<string, object>() { { "id", "1" }, { "name", "beck" } }));

                //var result = HCenter.CacheHelper.ExecUtils.PollyRetry<Exception, string>(Test, 5);
                //Console.WriteLine($"{DateTime.Now}result:{result}");

                Console.WriteLine($"{DateTime.Now} start");
                var result2 = HCenter.CacheHelper.ExecUtils.PollyWaitAndRetry<Exception, string>(Test, 5,3);
                Console.WriteLine($"{DateTime.Now} result2:{result2} end");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        private static string Test()
        {
            // 每执行一次加1
            times++;

            // 前2次都抛异常
            //if (times < 10)
            {
                throw new Exception("exception message");
            }
            return "success";
        }
    }

    public class Contact
    {
        public string Type { get; set; }

        public string Value { get; set; }

        public Contact(string type, string value)
        {
            this.Type = type;
            this.Value = value;
        }

    }

    public class Person
    {
        public long Id { get; set; }

        public int Age { get; set; }
        public string Name { get; set; }

        public List<Contact> Contacts { get; set; }

        public Person(long id, string name, List<Contact> contacts)
        {
            this.Id = id;
            this.Name = name;
            this.Contacts = contacts;
        }
    }
}
